import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;


public class IO
{
    // date format
    private static SimpleDateFormat dateFormat;
    private static SimpleDateFormat timeFormat;
    static
    {
        // month/day/year(12/10/2011)
        dateFormat = new SimpleDateFormat("MM/dd/yyyy");
        timeFormat = new SimpleDateFormat("HH:mm");
        
        // time zone GMT for simple times since we aren't using date
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
        timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
    }
    
    private String fileName;
    
    ///Input "" for filename if you'd like to specify at runtime
    public IO(String fileName)
    {
        this.fileName = fileName;
    }
    
    public List<TourOffering> readFile()
    {
        List<TourOffering> tourOfferings = new ArrayList<TourOffering>();
        
        try
        {
            // Open the file
            FileInputStream fStream = new FileInputStream(fileName);
            // Get the object of DataInputStream
            DataInputStream in = new DataInputStream(fStream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;
            
            Tour tour = null;
            Event event = null;
            TourOffering tourOffering = null;
            
            //Read File Line By Line
            while ((strLine = br.readLine()) != null)
            {
                if(strLine.isEmpty())
                    continue;
                
                switch(strLine.charAt(0))
                {
                    case '$': // print
                        System.out.println(strLine.substring(1));
                        continue;
                    case '-': // comment
                        continue;
                    case '0': //Tour
                        tour = parseTour(strLine);
                        break;
                    case '&': //Tabbed entry
                        // tour has been defined
                        if(tour != null)
                        {
                            // provider
                            if(strLine.charAt(1) == '&')
                            {
                                // add provider to latest event
                                if(event != null)
                                {
                                    parseProvider(strLine, event);
                                }
                            }
                            // event
                            else
                            {
                                event = parseEvent(strLine, tour);
                            }
                        }
                        break;
                    case '1': //Tour Offering
                        if(tour != null)
                        {
                            tourOffering = parseOffering(strLine, tour);
                            tourOfferings.add(tourOffering);
                        }
                        break;
                    case '2': //Reservation
                        if(tourOffering != null)
                        {
                            parseReservation(strLine, tourOffering);
                        }
                        break;
                    case '3':
                        if(tourOffering != null)
                        {
                            parseCancellation(strLine, tourOffering);
                        }
                        break;
                }
                
            }
            //Close the input stream
            in.close();
            return tourOfferings;
        }
        catch (FileNotFoundException e)
        {
            System.err.println("Error: " + e.getMessage());
        }
        catch (Exception e) 
        {//Catch exception if any
            System.err.println("Error: " + e.getMessage());
        }
        
        return null;
    }
    
    private void parseCancellation(String line, TourOffering tourOffering)
    {
        String[] strWords = splitStringToWords(line);
        String name = strWords[1];
        
        tourOffering.addCancellation(tourOffering.getReservation(name));
    }

    private Tour parseTour(String line)
    {
        Tour tour = null;
        String[] strWords = splitStringToWords(line);
        //Tour: StartPlace(string), EndPlace(string), ActivityLevel(int), MaxSize(int)
        String strPlace = strWords[1];
        //if strPlace already exsits, 
            //grab it
        //else
            Place startPlace = new Place(strPlace);
        strPlace = strWords[2];
        //if strPlace already exsits, 
            //grab it
        //else
            Place endPlace = new Place(strPlace);
            
        int actLevel =  Integer.parseInt(strWords[3]);
        int maxSize = Integer.parseInt(strWords[4]);
        
        tour = new Tour(startPlace, endPlace, actLevel, maxSize);
        return tour;
    }
    private Event parseEvent(String line, Tour tour)
    {
        Event event = null;
        String[] strWords = splitStringToWords(line);
        //Event: EventType(ACTIVITY,DINING,LODGING,TRAVEL), StartTime(Time), EndTime(Time)
        EventType type = null;
        String strType = strWords[1];
        Time startTime = null, endTime = null;
        try
        {
            startTime = new Time(timeFormat.parse(strWords[2]).getTime());
            endTime = new Time(timeFormat.parse(strWords[3]).getTime());
        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        if(0 == strType.compareTo("activity"))
            type = EventType.ACTIVITY;
        else if(0 == strType.compareTo("dining"))
            type = EventType.DINING;
        else if(0 == strType.compareTo("lodging"))
            type = EventType.LODGING;
        else if(0 == strType.compareTo("travel"))
            type = EventType.TRAVEL;
        
      
        event = new Event(type, startTime, endTime);//Event event = new Event(type, place, startTime, endTime);
        String d = String.valueOf(line.charAt(1));
        int day = Integer.parseInt(d);
        tour.addEvent(day, event);
        return event;
    }
    private TourOffering parseOffering(String line, Tour tour)
    {
        TourOffering tourOffering = null;
        String[] strWords = splitStringToWords(line);
        //TourOffering: StartDate(Date)
        try
        {
            tourOffering = new TourOffering(dateFormat.parse(strWords[1]));
        }
        catch (ParseException e)
        {
            e.printStackTrace();
        }
        tourOffering.setTour(tour);
        return tourOffering;
    }
    private void parseProvider(String line, Event event)
    {
        Provider provider = null;
        String[] strWords = splitStringToWords(line);
        //Provider: Name(string), Place(string), Capacity(int), OpenTime(Time), CloseTime(Time)
        String name = strWords[1];
        Place place = new Place(strWords[2]);
        int capacity = Integer.parseInt(strWords[3]);
        
        Time openTime = null, closeTime = null;
        try
        {
            openTime = new Time(timeFormat.parse(strWords[4]).getTime());
            closeTime = new Time(timeFormat.parse(strWords[5]).getTime());
        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        provider = new Provider(name, place, capacity, openTime, closeTime);
        
        try
        {
            event.addProvider(provider);
        }
        catch(NotOpenException noe)
        {
            System.out.println("Error adding provider " + provider.getName() + ": Not open duing event time.");
        }
    }
    public void parseReservation(String line, TourOffering tourOffering)
    {
        Reservation reservation = null;
        Traveler traveler = null;
        String[] strWords = splitStringToWords(line);
        
        //Reservation: Name(string), FitnessRating(int), RoomType(PARTNER,SOLO,SINGLE), PartnerName(string)[only if type is partner will this be read in]
        String name = strWords[1];
        int fitnessRating = Integer.parseInt(strWords[2]);
        
        // check that fitness rating is good enough for tour activity level
        if (fitnessRating < tourOffering.getTour().getActivityLevel())
        {
            System.out.println("Cannot make reservation for " + name + " because fitness level is too low for tour.");
        }
        
        traveler = new Traveler(name, fitnessRating);
        String strType = strWords[3];
        
        if(0 == strType.compareTo("partner"))
        {
            name = strWords[4];
            fitnessRating = Integer.parseInt(strWords[5]);
            Traveler partner = new Traveler(name, fitnessRating);
            reservation = new Reservation(traveler, partner);
            
            // we need to add the partner
            tourOffering.addReservation(new Reservation(partner, traveler));
        }
        else
        {
            boolean wantsRoomate = false;
            if(0 == strType.compareTo("solo"))
                wantsRoomate = true;
            
            reservation = new Reservation(traveler, wantsRoomate);
        }
        tourOffering.addReservation(reservation);
    }
    
    public String[] splitStringToWords(String line)
    {
        line = line.toLowerCase();
        //Split line into words
        String[] strWords = line.split(", ");
        return strWords;
    }
}


